home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
graphics
/
dxlib50.zip
/
EASYX.DOC
< prev
next >
Wrap
Text File
|
1995-02-11
|
28KB
|
847 lines
EASYX PROGRAMMER'S MANUAL
VERSION 2.0
(DOS Extender Library)
TechniLib Company
Copyright 1993-1995, by TechniLib (TM) Company
All Rights Reserved
TERMS OF USE AND DISTRIBUTION
XLIB is a shareware product; therefore, unregistered copies of XLIB are
made available free of charge so that potential purchasers will have the
opportunity to examine and test the software before committing payment.
Distribution of unregistered copies of XLIB to other potential users is also
permitted and appreciated. However, usage and distribution of XLIB must
conform to the following conditions. In the following statement, the term
"commercial distribution," includes shareware distribution.
1) XLIB and accompanying software must be distributed together in copies of
the original archive provided by TechniLib. Neither the archive nor
individual files therein may be modified.
2) The XLIB archive may be distributed in combination with other shareware
products; however, the XLIB archive may not be distributed with other
commercially distributed software without written consent of TechniLib.
3) Copies of XLIB which have been used to develop software for commercial
distribution must be registered before such software is marketed. Copies of
XLIB which have been used to develop noncommercial software must be registered
if such software is to be regularly used either by the developer or others.
4) Commercially distributed software must embed XLIB procedures in the
software code. Files contained in the XLIB archive may not be placed in the
distribution media.
5) XLIB is designed to offer a set of services to other executable code. XLIB
may not be used to develop software for commercial distribution which will
essentially offer any of these same services to other executable code.
Exceptions to this condition require written consent of TechniLib.
6) Rights afforded by registering a single copy of XLIB pertain only to a
single computer.
7) XLIB may be registered for a fee of $50.00 per copy. Accompany payment
with return address. Registrants will be entitled to the most recent version
of the XLIB archive.
DISCLAIMER OF WARRANTY
XLIB AND ALL ACCOMPANYING SOFTWARE AND LITERATURE ARE DISTRIBUTED WITH
THE EXCLUSION OF ANY AND ALL IMPLIED WARRANTIES, AND WITH THE EXCLUSION OF
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. TechniLib
SHALL HAVE NO LIABILITY FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
RESULTING FROM THE USE OF XLIB OR ACCOMPANYING MATERIALS. The user assumes
the entire risk of using this software.
Copyright 1993-1995, by TechniLib (TM) Company
All Rights Reserved
TABLE OF CONTENTS
CHAPTERS
Page
1. Introduction 1
2. Initialization of EASYX 2
3. Memory Management 3
4. Memory-Mapped Input/Output 6
5. File Management 7
EXAMPLES
Page
1. EASYX Memory Management 5
2. EASYX File Management 10
1. Introduction
EASYX is a DOS extender library intended for programmers who are
unfamiliar with assembly language. EASYX allows real-mode high-level
languages to perform transfers between extended memory and conventional memory
or between extended memory and disk files. Many programmers need a DOS
extender merely to afford real-mode languages access to extended memory. In
such cases, EASYX is a simple and powerful alternative.
EASYX is actually little more than a real-mode interface to XLIB. The
source code for EASYX is supplied in the XLIB archive (EASYX.ASM). Assembly
language programmers may be interested in examining this code to learn more
about working with XLIB. This code has been assembled and then linked with
XLIB.LIB to create EASYX.LIB.
The EASYX library is provided in two formats - one for Microsoft
languages and the other for Borland languages. Microsoft programmers should
use EASYX.LIB. Borland programmers should use EASYXB.LIB. The respective C
header files are EASYX.H and EASYXB.H. Programmers using other languages will
have to write their own prototypes for EASYX procedures. These prototypes
should declare all EASYX procedures as far procedures conforming to the PASCAL
calling and naming convention. Prototypes for Microsoft BASIC 7.0 are
presented in the files EASYXEX1.BAS and EASYXEX2.BAS.
The programmer might prefer to use EASYXE.LIB rather than EASYX.LIB. The
former has CPU exception trapping capabilities whereas the latter does not.
EASYXE.LIB will always trap exceptions occurring in protected mode. It can
also trap real-mode exceptions provided that a DPMI 1.0 host is installed.
Borland programmers should use EASYXEB.LIB. C and C++ programmers should
continue to use EASYX.H or EASYXB.H for header files.
Most EASYX procedures can return error codes. These are always XLIB
error codes. The codes are explained in the XLIB documentation.
1
2. Initialization of EASYX
EASYX requires no initialization; however, the XLIB library which has
been linked with EASYX must be initialized before any EASYX procedures are
called. XLIB is initialized by calling INITXLIB. INITXLIB returns an error
code in DX:AX; therefore, it should be implemented as a long integer function.
The following code demonstrates initialization in Microsoft C:
extern unsigned long __far __pascal INITXLIB(void);
void main(void)
{
unsigned long errcode;
errcode = INITXLIB();
if(errcode != 0)
{
printf("Initialization error: %lX",errcode);
return;
}
.
.
.
An explanation of possible error codes is presented in the XLIB
documentation. The most common error is caused by insufficient conventional
memory. INITXLIB will attempt to allocate a small amount of conventional
memory through DOS; however, many high-level languages automatically claim all
available DOS memory, even though only a small percentage of this memory may
actually be used. The programmer must therefore release a portion of this
memory back to DOS before calling INITXLIB. This process is illustrated for
the Borland Turbo Assembler in the file EXAMP1B.ASM, and for Microsoft BASIC
in EASYXEX1.BAS. C and C++ programmers need not be concerned with this matter
because these languages allocate DOS memory dynamically.
2
3. Memory Management
High-level languages confined to real mode are incapable of addressing
extended memory; consequently, such languages must communicate with extended
memory through buffers in conventional memory. EASYX provides several
procedures to facilitate this process.
Extended memory should always be allocated with the procedure XMALLOC
before it is addressed. Attempted transfers to or from unallocated memory may
lead to page faults (exception 14), or to corruption of resident software.
XMALLOC returns a long integer error code; therefore, it should be implemented
as a long integer function. The following Microsoft C prototype shows the
structure of XMALLOC:
extern unsigned long __far __pascal XMALLOC(unsigned long nobytes, unsigned
long __far *address, unsigned long __far *size, unsigned long __far
*handle);
where:
nobytes = The requested size for the extended memory block.
*address = A far pointer to an unsigned long integer variable which will
receive the linear address of the allocated block.
*size = A far pointer to an unsigned long integer variable which will
receive the actual size of the allocated extended memory block.
The actual size will always be at least as large as the requested
size.
*handle = A far pointer to an unsigned long integer variable which will
receive a handle for the allocated extended memory block. The
handle must be used to release the block.
An extended memory block can be released with the XFREE procedure. XFREE
is also a long integer function which returns an error code. The C prototype
of this procedure is:
extern unsigned long __far __pascal XFREE(unsigned long handle);
where: handle = The handle assigned to the block by XMALLOC.
All extended memory is automatically released upon program termination;
consequently, XFREE will not be necessary for most programs.
If DPMI 1.0 is installed, then version 2.0 of EASYX has the ability to
manage uncommitted memory. Uncommitted memory is a logical address space with
no physical memory assigned to it. Physical memory is committed (mapped) to
addresses within the space when they are accessed. Uncommitted memory becomes
useful when a program needs to manage an array of uncertain size. The array
can be dimensioned to be very large without exhausting physical memory by
situating the array over uncommitted memory. Large amounts of memory will
therefore be used only when it is needed.
The procedure for allocating uncommitted memory is XUMALLOC. It has
exactly the same prototype as XMALLOC.
3
After physical memory has been mapped into an uncommitted address space,
the programmer might wish to restore part or all of the address space back to
uncommitted state. This releases the physical memory allocated to the space
so that it can be used for other purposes. EASYX contains a routine called
XUNCOMMIT to perform such tasks. The C prototype for this routine is:
extern unsigned long __far __pascal XUNCOMMIT(unsigned long handle, unsigned
long startoffset, unsigned long nobytes)
where:
handle = The handle of a memory block previously allocated with XUMALLOC.
startoffset = The offset within the block at which memory is to be released.
nobytes = The number of bytes to release.
DPMI hosts will almost invariable map physical memory at 1000H boundaries
and in units of 1000H bytes. Therefore, both startoffset and nobytes should
be even multiples of 1000H (4096). If this is not the case, then XUNCOMMIT
will round these variables down to the next even multiple.
XUNCOMMIT releases physical memory backing an address space, but not the
address space itself. Use XFREE to release both the address space and all
physical memory mapped within it.
Transfers between conventional memory and extended memory can be
accomplished with the MOVMEM procedure. The prototype for MOVMEM is:
extern void __far __pascal MOVMEM(unsigned long destadr, unsigned long
sourceadr, unsigned long nobytes);
where:
destadr = The linear address of the destination memory.
sourceadr = The linear address of the source memory.
nobytes = The number of bytes to be transferred.
MOVMEM may actually be used to transfer memory between any source and
destination. The destination block and source block may also be overlapped.
MOVMEM transfers are faster than XMS or INT 15H because MOVMEM uses 32-
bit instructions. MOVMEM also exposes to less risk of losing an interrupt.
MOVMEM is a reentrant procedure, so it may be safely called within
interrupt handlers. When MOVMEM is being used in a hardware interrupt
handler, the handler should be installed after the call to INITXLIB to prevent
a call to MOVMEM before protected-mode structures have been initialized.
Real-mode programs use segment addresses instead of linear addresses.
EASYX includes a procedure called LINADR which computes linear addresses from
segment addresses. The prototype for LINADR is:
extern unsigned long __far __pascal LINADR(void __far *ptr);
The following program uses the procedures presented in this section. The
file EASYXEX1.BAS contains a Microsoft BASIC 7.0 version of the program.
4
Example 1: EASYX Memory Management
_____________________________________________________________________________
#include <stdio.h>
#include <easyx.h>
void main(void)
{
unsigned long errcode, nobytes, xaddress, xsize, xhandle, bufferaddress;
long buffer[1024]; /*4k buffer*/
errcode = INITXLIB(); /*Initialize XLIB*/
if(errcode != 0)
{
printf("Library initialization error: %lX\n",errcode);
return;
}
nobytes = 0x10000; /*Allocate 64k of extended memory*/
errcode = XMALLOC(nobytes, &xaddress, &xsize, &xhandle);
if(errcode != 0)
{
printf("Memory allocation error: %lX\n",errcode);
return;
}
bufferaddress = LINADR(buffer); /*Get linear address of buffer*/
MOVMEM(xaddress, bufferaddress, 4096); /*Transfer buffer to extended*/
MOVMEM(bufferaddress, xaddress, 4096); /*Transfer extended to buffer*/
errcode = XFREE(xhandle); /*Release the extended memory*/
if(errcode != 0)
printf("Memory release error: %lX\n",errcode);
}
_____________________________________________________________________________
5
4. Memory-Mapped Input/Output
On 386 and higher machines, memory reads and writes may undergo address
translation so that the address which is physically accessed may be different
from the address specified in the read/write instruction. The physically
accessed address is the "physical address." The address specified by the
read/write instruction is the "logical address." Normally programmers need
not be concerned with the difference; however, this is not the case if the
program must access an IO device which maps to a fixed physical address. In
such cases, the programmer must obtain a logical address which corresponds to
the physical address of the IO device. EASYX contains a procedure called
MAPIOMEM which will map a specified physical address into a logical address
space. MAPIOMEM is a long integer function which returns an error code. The
prototype for MAPIOMEM is:
extern unsigned long __far __pascal MAPIOMEM(unsigned long physaddress,
unsigned long size, unsigned long __far *logaddress);
where:
physaddress = The beginning physical address for the IO device.
size = The size of the physical address block in bytes.
*logaddress = A far pointer to an unsigned long integer which is to receive
the assigned logical address. Access the IO device at this
address.
MAPIOMEM will sometimes return errors upon attempts to map physical
addresses in the first megabyte.
6
5. File Management
EASYX includes procedures which can transfer data between extended memory
and files. These procedures can load files to extended memory or save
extended memory to files. They can read and write files either sequentially
or randomly.
All EASYX file management routines will receive and return values in a
contiguous block of memory called a "file control block" (not to be confused
with DOS file control blocks). The file control block must be located in
conventional memory and must have the following form:
Field Name Field Type Field Description
---------- ---------- -----------------
CONDCODE unsigned long Condition code from file operation
FNAME char[68] File path and name (zero terminated string)
FHANDLE unsigned int File handle assigned by DOS
FPTRMODE unsigned int File pointer mode
FPTR unsigned long File pointer
BLKADR unsigned long Memory source/destination address
BLKSIZE unsigned long Size of source/destination block in bytes
BUFADR unsigned long Buffer address (conventional memory)
BUFSIZE unsigned int Buffer size in bytes
CONTROL unsigned int Control word
CONDCODE is used to return error codes. CONDCODE should be situated at
the starting address of the control block.
FNAME is a zero-terminated ASCII string defining the file path and name.
There cannot be more than 68 characters in this string, including the
termination character.
BLKADR and BLKSIZE define the source/destination memory block for the
transfer. This block may be in either conventional or extended memory.
BLKADR is a linear address.
XLIB uses DOS to access the disk. DOS cannot read or write to extended
memory; consequently, a conventional memory buffer must be set up for the DOS
transfers. File management routines shift to protected mode to perform
transfers between the buffer and the source/destination memory. BUFADR and
BUFSIZE define the conventional memory buffer. BUFADR is a linear address.
For fastest transfers, the memory block and the buffer should be DWORD
aligned and should have sizes equal to an integer multiple of four.
FPTR and FPTRMODE specify the file pointer setting to be used before
intrafile transfers to or from the disk. FPTRMODE specifies how FPTR is to be
interpreted. The following values are valid for FPTRMODE:
FPTRMODE FPTR Interpretation
-------- -------------------
0 Unsigned offset from the beginning of the file
1 Signed offset from the current file pointer
2 Signed offset from the end of the file
3 FPTR is ignored. Use current file pointer (sequential mode)
7
CONTROL is not used in the present version of EASYX. All bits in control
should be set to zero.
Since these routines perform disk operations, special precautions should
be taken to ensure that parameters in the file control block are properly
defined before performing calls. In particular, one should always make sure
that the source/destination memory block and the conventional memory buffer
are properly defined. A safe rule is to simply set the buffer size to zero
because this forces EASYX to supply a buffer when opening or creating the
file.
EASYX file routines should not be called within interrupt handlers
because all of these routines use DOS.
All EASYX file routines receive a single argument; namely, the far
address of the control block. Prototypes for the file routines are:
extern void __far __pascal XFCREATE(void __far *controlblock);
extern void __far __pascal XFOPEN(void __far *controlblock);
extern void __far __pascal XFCLOSE(void __far *controlblock);
extern void __far __pascal XFLOAD(void __far *controlblock);
extern void __far __pascal XFSAVE(void __far *controlblock);
extern void __far __pascal XFREAD(void __far *controlblock);
extern void __far __pascal XFWRITE(void __far *controlblock);
The following is a detailed explanation of each of these procedures:
XFCREATE (Create File)
Purpose: Create and open a new file of specified name in specified directory.
Control Block at Call: FNAME = file path and name.
Control Block at Return: CONDCODE = error code. If CONDCODE = 0, then
FHANDLE = file handle assigned by DOS. If the procedure is called with
BUFSIZE = 0, then EASYX will set BUFADR and BUFSIZE to its own internal
buffer.
Details:
If the file already exists, then it will be truncated to zero length.
Files created by this routine will be given both read and write access.
XFOPEN (Open File)
Purpose: Open existing file of specified name in specified directory.
Control Block at Call: FNAME = file path and name.
Control Block at Return: CONDCODE = error code. If CONDCODE = 0, then
FHANDLE = file handle assigned by DOS. If the procedure is called with
BUFSIZE = 0, then EASYX will set BUFADR and BUFSIZE to its own internal
buffer.
Details: The file is opened for both read and write access.
XFCLOSE (Close File)
Purpose: Close previously opened file.
Control Block at Call: FHANDLE = file handle.
Control Block at Return: CONDCODE = error code.
8
XFSAVE (Save File)
Purpose: Create file with contents equal to specified memory block.
Control Block at Call: FNAME = file path and name. BLKADR/BLKSIZE = address
and size of memory block to provide file contents. BUFADR/BUFSIZE = address
and size of conventional memory buffer.
Control Block at Return: CONDCODE = error code.
Details:
The file cannot already be open. The file is both created and closed by
this routine.
This routine will replace any previously existing file named FNAME.
BLKADR/BLKSIZE may define a conventional memory block provided that this
block is not overlapped by BUFADR/BUFSIZE.
If this routine is called with BUFSIZE = 0, then EASYX will automatically
supply a buffer.
XFLOAD (Load File)
Purpose: Load file contents to specified memory block.
Control Block at Call: FNAME = file path and name. BLKADR/BLKSIZE = address
and size of memory block to receive file contents. BUFADR/BUFSIZE = address
and size of conventional memory buffer.
Control Block at Return: CONDCODE = error code. If CONDCODE = 0, then
BLKSIZE = actual number of bytes transferred.
Details:
The file cannot already be open. The file is both opened and closed by
this routine.
The value of BLKSIZE as of call is interpreted as an upper limit on the
number of bytes to transfer. The entire file is loaded provided that it does
not contain more than BLKSIZE bytes.
BLKADR/BLKSIZE may define a conventional memory block provided that this
block is not overlapped by BUFADR/BUFSIZE.
If this routine is called with BUFSIZE = 0, then EASYX will automatically
supply a buffer.
XFWRITE (Write to File)
Purpose: Write specified memory block to specified location in open file.
Control Block at Call: FHANDLE = file handle. FPTR/FPTRMODE = file pointer
setting for beginning of transfer. BLKADR/BLKSIZE = address and size of
memory block to provide file contents. BUFADR/BUFSIZE = address and size of
conventional memory buffer.
Control Block at Return: CONDCODE = error code.
Details:
The file must be opened with XFOPEN or XFCREATE before using this routine.
BLKADR/BLKSIZE may define a conventional memory block provided that this
block is not overlapped by BUFADR/BUFSIZE.
Sequential transfers should set FPTRMODE = 3 for fastest execution.
XFREAD (Read From File)
Purpose: Load specified memory block from specified location in open file.
Control Block at Call: FHANDLE = file handle. FPTR/FPTRMODE = file pointer
setting for beginning of transfer. BLKADR/BLKSIZE = address and size of
memory block to receive file contents. BUFADR/BUFSIZE = address and size of
conventional memory buffer.
Control Block at Return: CONDCODE = error code. If CONDCODE = 0, then
BLKSIZE = the actual number of bytes transferred.
9
Details:
The file must be opened with XFOPEN or XFCREATE before using this routine.
BLKADR/BLKSIZE may define a conventional memory block provided that this
block is not overlapped by BUFADR/BUFSIZE.
Sequential transfers should set FPTRMODE = 3 for fastest execution.
The following C program illustrates the usage of some of the above
procedures. A BASIC translation of this program is in EASYXEX2.BAS.
Example 2: EASYX File Management
_____________________________________________________________________________
#include <stdio.h>
#include <string.h>
#include <easyx.h>
void main (void)
{
unsigned int i;
unsigned long errcode, nobytes, xaddress, xsize, handle, arrayaddress;
int array[100];
struct xfile fb; /*Declare file control block*/
errcode = INITXLIB(); /*Initialize XLIB*/
if(errcode != 0)
{
printf("Library initialization error: %lX\n",errcode);
return;
}
nobytes = 0x10000; /*Allocate 64k of extended memory*/
errcode = XMALLOC(nobytes,&xaddress,&xsize,&handle);
if(errcode != 0)
{
printf("Extended memory allocation error: %lX\n",errcode);
return;
}
for(i = 0; i < 100; i++) /*Put something in array[]*/
array[i] = i;
arrayaddress = LINADR(array); /*Compute linear address of array[]*/
fb.condcode = 0; /*Set control block to create file*/
strcpy(fb.fname,"junk.dat"); /*Specify file name*/
fb.blkadr = arrayaddress; /*Will transfer array[] to the file*/
fb.blksize = 200; /*There are 200 bytes in array[]*/
fb.bufsize = 0; /*Force XLIB to use its internal buffer*/
XFSAVE(&fb); /*Create file and save array[] to it*/
if(fb.condcode != 0)
{
printf("File save error: %lX\n",fb.condcode);
return;
}
10
XFOPEN(&fb); /*Reopen the file*/
if(fb.condcode != 0)
{
printf("File open error: %lX\n",fb.condcode);
return;
}
fb.blkadr = xaddress; /*Prepare to transfer the file to extended*/
fb.blksize = 100; /*Will transfer only 100 bytes*/
fb.fptrmode = 0; /*File pointer is relative to start of file*/
fb.fptr = 100; /*Set file pointer to 50th element*/
XFREAD(&fb); /*Read last 50 elements to extended*/
if(fb.condcode != 0)
{
printf("File read error: %lX\n",fb.condcode);
return;
}
MOVMEM(arrayaddress,xaddress,100); /*Transfer file contents back to array[]
XFCLOSE(&fb); /*Close the file*/
if(fb.condcode != 0)
{
printf("File close error: %lX\n",fb.condcode);
return;
}
errcode = XFREE(handle); /*Release extended memory*/
if(errcode != 0)
{
printf("Memory release error: %lX\n",errcode);
return;
}
}
_____________________________________________________________________________
11